package com.woohua.demo.seal;

import cn.hutool.core.util.ArrayUtil;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.exporting.PdfImageInfo;
import com.spire.pdf.graphics.PdfImage;
import com.spire.pdf.widget.PdfPageCollection;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPageTree;
import org.apache.pdfbox.rendering.PDFRenderer;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;

/***
 * @title PdfSeal
 * @description
 * @author woo hua
 * @version 1.0.0
 * @create 2023/1/13 14:15
 **/
@Slf4j
public class PdfSealUtils {


    /**
     * 临时目录的路径
     */
    public static final String TEMP_DIR_PATH = "/tmp/pdf_seal/";

    public static final String TEMP_DIR_PATH_WIN = "D:/tmp/pdf_seal/";


    /**
     * 盖章-通过替换图片
     *
     * @param imagePos ： 2：（互联网医院章 || 已作废）
     * @return 盖章后文件地址
     */
    public static String sealBySpire(String filePath, String filename, int imagePos, EnumTypes.IconSealType iconSealType) {
        log.info("===============开始pdf文件盖章===================");
        //加载PDF文档
        PdfDocument pdf = new PdfDocument();
        pdf.loadFromFile(filePath);

        PdfPageCollection pages = pdf.getPages();

        int imgCount = 0;

        for (int i = 0; i < pages.getCount(); i++) {
            PdfPageBase page = pages.get(i);
            PdfImageInfo[] imagesInfo = page.getImagesInfo();
            imgCount += imagesInfo.length;


            // 需要替换图片的页
            if (imagePos <= imgCount) {
                String iconPath = getIconResourcePath(iconSealType);
                //加载一张图片
                PdfImage image = PdfImage.fromFile(iconPath);
                // 需要替换当前页的第几张图片
                int rPos = imagePos - imgCount + imagesInfo.length;

                log.info("PDF的第{}页，当前页图片个数：{}, 替换第{}张图片", i + 1, imagesInfo.length, rPos);
                //使用加载的图片替换第一页上的第一张图片
                page.replaceImage(rPos - 1, image);
                break;
            }
        }
        if (imagePos > imgCount) {
            log.error("图片位置不正确，参数imagePos：{}, 不能超过最大图片数：{}", imagePos, imgCount);
        }

        String tempFilePath = getTempDir() + filename;
        //保存文档
        pdf.saveToFile(tempFilePath);
        pdf.dispose();
        log.info("===============pdf文件盖章完成===================");
        return tempFilePath;
    }

    private static String getIconResourcePath(EnumTypes.IconSealType iconSealType) {
        String tempDir = getTempDir();

        // 项目相对路径，无法通过jar获取
        File file = new File(tempDir + iconSealType.getName());
        if (file.exists()) {
            log.info("盖章文件已被创建， 绝对路径：{}", file.getAbsolutePath());
            return tempDir + iconSealType.getName();
        }
        try {
            InputStream is = PdfSealUtils.class.getResourceAsStream(iconSealType.getName());
            FileUtils.copyInputStreamToFile(is, file);
        } catch (IOException e) {
            log.error("获取盖章图标失败，失败原因：{}", e);
        }
        log.info("盖章文件绝对路径：{}", file.getAbsolutePath());
        return file.getAbsolutePath();
    }

    private static String getTempDir() {
        String osName = System.getProperty("os.name");
        String tempDir = osName.startsWith("Windows") ? TEMP_DIR_PATH_WIN : TEMP_DIR_PATH;
        File dic = new File(tempDir);
        if (!dic.isDirectory()) {
            // 生成临时目录
            dic.mkdirs();
        }
        return tempDir;
    }


    public static final Base64.Encoder ENCODER = Base64.getEncoder();
    public static final Base64.Decoder DECODER = Base64.getDecoder();

    /***
     * pdfBase64转图片，返回base64编码集合
     *
     * @param pdfBase64  pdf类型base64
     * @return List<String>
     */
    public static List<String> pdfToImageBase64(String pdfBase64) {
        PDDocument doc = null;
        ByteArrayOutputStream os = null;
        List<String> list = new ArrayList();
        ByteArrayInputStream stream = null;

        try {
            if (StringUtils.isEmpty(pdfBase64)) {
                return list;
            }
            //base64解码
            byte[] bytes = DECODER.decode(pdfBase64);
            stream = new ByteArrayInputStream(bytes);
            // 加载解析PDF文件
            doc = PDDocument.load(stream);
            PDFRenderer pdfRenderer = new PDFRenderer(doc);
            PDPageTree pages = doc.getPages();
            int pageCount = pages.getCount();
            for (int i = 0; i < pageCount; i++) {
                BufferedImage bim = pdfRenderer.renderImageWithDPI(i, 200);
                os = new ByteArrayOutputStream();
                ImageIO.write(bim, "jpg", os);
                byte[] dataList = os.toByteArray();
                //base64编码
                list.add(ENCODER.encodeToString(dataList));
            }
        } catch (Exception e) {
            log.error("加载解析PDF文件失败，失败原因：{}", e);
        } finally {
            try {
                if (doc != null) {
                    doc.close();
                }
                if (os != null) {
                    os.close();
                }
                if (stream != null) {
                    stream.close();
                }
            } catch (Exception e) {
                log.error("加载解析PDF文件 关闭IO流失败，失败原因：{}", e);
            }
        }
        return list;
    }

    /***
     * pdfBase64转图片，返回base64编码集合
     *
     * @param bytes  base64解码字节数组
     * @return List<String>
     */
    public static List<String> pdfToImageBase64(byte[] bytes) {
        PDDocument doc = null;
        ByteArrayOutputStream os = null;
        List<String> list = new ArrayList();
        ByteArrayInputStream stream = null;

        try {
            if (ArrayUtil.isEmpty(bytes)) {
                return list;
            }
            stream = new ByteArrayInputStream(bytes);
            // 加载解析PDF文件
            doc = PDDocument.load(stream);
            PDFRenderer pdfRenderer = new PDFRenderer(doc);
            PDPageTree pages = doc.getPages();
            int pageCount = pages.getCount();
            for (int i = 0; i < pageCount; i++) {
                BufferedImage bim = pdfRenderer.renderImageWithDPI(i, 200);
                os = new ByteArrayOutputStream();
                ImageIO.write(bim, "jpg", os);
                byte[] dataList = os.toByteArray();
                //base64编码
                list.add(ENCODER.encodeToString(dataList));
            }
        } catch (Exception e) {
            log.error("加载解析PDF文件失败，失败原因：{}", e);
        } finally {
            try {
                if (doc != null) {
                    doc.close();
                }
                if (os != null) {
                    os.close();
                }
                if (stream != null) {
                    stream.close();
                }
            } catch (Exception e) {
                log.error("加载解析PDF文件 关闭IO流失败，失败原因：{}", e);
            }
        }
        return list;
    }

    public static void main(String[] args) {
        sealBySpire("D:\\pdf\\崔建彬2023010219312515296.pdf", "崔建彬2023010219312515296.pdf", 4, EnumTypes.IconSealType.ICON_SEAL_DEPARTMENT);
    }
}
